<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>

    <link rel="stylesheet" type="text/css" 
      href="/assets/css/straybirds.css" media="screen" />
    <link rel="stylesheet" type="text/css" 
      href="/assets/css/pygments.css" media="screen" />

    <!-- MathJax Section Start -->

    <script type="text/javascript"
    src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
    </script>
    <script>
        MathJax.Hub.Config({
              tex2jax: {
              skipTags: ['script', 'noscript', 'style', 'textarea', 'pre']
              }
        });
        MathJax.Hub.Queue(function() {
            var all = MathJax.Hub.getAllJax(), i;
            for(i=0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

    <!-- MathJax Section End -->

    <!-- Google Analytics Start-->
    <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-48100787-1', 'minixalpha.github.io');
  ga('send', 'pageview');

</script>

    <!-- Google Analytics End -->

    <title>字符指针与字符数组真正的区别</title>
  </head>

  <body>
    <div class="container">
      <header>
        <div class="container">
          <h1>
              <a href="/" title="Home Page"> 潇湘夜雨 </a>
          <span class="github-src">
            <a href ="https://github.com/minixalpha/minixalpha.github.io"
               target="_blank"
               title="Fork me on GitHub">
              <img src="/assets/images/GitHub-Mark-Light-32px.png" alt="">
            </a>
          </span>
          </h1>
        </div>
      </header>

      <aside id="left-side">
        <h2> 分类 </h2>
  <ul class="category-list">
      
            
                <li>
                <a href="/categories/源代码阅读"> 源代码阅读 (20) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/设计模式"> 设计模式 (3) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/科研"> 科研 (6) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/思想"> 思想 (2) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/技术"> 技术 (18) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/工具"> 工具 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/虚拟机"> 虚拟机 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/java"> java (11) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/c语言"> c语言 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/读书"> 读书 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/操作系统"> 操作系统 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/英语"> 英语 (10) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/计算机系统"> 计算机系统 (3) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/生活"> 生活 (1) </a>
                </li>
            
      
  </ul>

      </aside>

      <aside id="right-side">
        <h2> 归档 </h2>
  <ul class="archive-list">
    
    
    
        
        
        
        
            
            <li>
                <a href="/2014/08">
                    2014-08 (1)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/07">
                    2014-07 (5)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/05">
                    2014-05 (12)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/04">
                    2014-04 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/03">
                    2014-03 (11)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/02">
                    2014-02 (6)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/01">
                    2014-01 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/11">
                    2013-11 (10)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/10">
                    2013-10 (3)
                </a>
            </li>

        
        
    
        
        
        
        
            
            <li>
                <a href="/2010/09">
                    2010-09 (1)
                </a>
            </li>

        
        
    
  </ul>

      </aside>

      <article>

<h1>字符指针与字符数组真正的区别</h1>

<hr>

<h2>问题缘起</h2>

<p>先看一个示例</p>

<h3>示例1</h3>
<div class="highlight"><pre><code class="c language-c" data-lang="c"><span class="cp">#include &lt;stdio.h&gt;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="s">&quot;hello&quot;</span><span class="p">;</span>
    <span class="kt">char</span> <span class="n">q</span><span class="p">[]</span> <span class="o">=</span> <span class="s">&quot;hello&quot;</span><span class="p">;</span>

    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;p: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">p</span><span class="p">);</span>
    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;q: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">q</span><span class="p">);</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>上面的例子会给出这样的输出</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">p: hello
q: hello
</code></pre></div>
<p>这样看，<code>char *p</code> 和 <code>char q[]</code> 好像没什么区别, 那么我们再看一个例子</p>

<h3>示例2</h3>
<div class="highlight"><pre><code class="c language-c" data-lang="c"><span class="cp">#include &lt;stdio.h&gt;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="s">&quot;hello&quot;</span><span class="p">;</span>
    <span class="kt">char</span> <span class="n">q</span><span class="p">[]</span> <span class="o">=</span> <span class="s">&quot;hello&quot;</span><span class="p">;</span>

    <span class="n">p</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;s&#39;</span><span class="p">;</span>
    <span class="n">q</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;s&#39;</span><span class="p">;</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>如果你在Linux下，运行时可能得到这样的结果</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">Segmentation fault (core dumped)
</code></pre></div>
<p>这时候你看到了区别，出现了段错误, 你一定想明白，到底发生了什么，
经过几个小实验，你可能会发现使用 <code>char *p</code> 定义时，p指向的数据是无法改变的。
然后你Google, 别人可能会告诉你  </p>

<ul>
<li>char 指针指向的数据不能修改</li>
<li>char 指针指向的数据没有分配</li>
<li>...</li>
</ul>

<p>你听了还是一头雾水，不能修改是什么意思，没有分配？没有分配为什么能输出?</p>

<p>作为一个好奇心很重的人，你是绝对不能容忍这些问题的困扰的，且听我慢慢道来</p>

<hr>

<h2>深入理解</h2>

<p>首先，你的程序代码和程序数据都在内存里放着，也就是说 p 指向的 <code>hello</code> 和 q 指向的 <code>hello</code>, 
都是内存中的数据。从两个示例的比较中，你发现，同样是内存中的数据，都可以读，但是有的可以写，
有的不能写。从这可以看出，问题的关键在于，内存是如何组织的。  </p>

<p>写好的程序代码放在硬盘上。程序代码的运行需要CPU一条指令一条指令地执行。</p>

<blockquote>
<p>在硬盘上读东西是慢的，CPU是快的，所以有了内存。</p>
</blockquote>

<p>因此程序代码如果要运行，需要先载入内存。这时候，问题又出现了，系统中同时有许多程序要运行，
你想要这块内存，我也想要这块内存，那这块内存给谁呢？ 何况，写程序的时候，我是不知道哪块内存
被占用，哪块没有被占用的。总不能每次我想放数据，都检查一下吧。那程序员的负担也太大了。</p>

<blockquote>
<p>一件事如果大家都需要，肯定会出现专门做这件事的人。</p>
</blockquote>

<p>于是，操作系统接管了内存。程序A说，我要12号内存单元。程序B说，我要12号内存单元。
操作系统表示很为难。不能都给，要不就冲突了，也不能不给，内存还有好大地方呢。</p>

<blockquote>
<p>操作系统是聪明的，聪明人是会抽象的。</p>
</blockquote>

<p>所谓抽象，就是看不到具体的东西了，只能看到上层的东西。当程序A和程序B都请求12号内存单元时，
操作系统把3号内存单元给了A，5号内存单元给了B。但是为了让程序中对内存的访问保持一致性，
并不让程序知道给他们的不是12号内存单元,否则程序中凡是和12号内存单元相关的，都要作修改，
又变成了程序自己维护内存。操作系统为每个程序维护一个映射表。在映射表中，
对于程序A来说，12号内存单元对应3号内存单元，对于程序B来说12号内存单元对应5号内存单元。
这时候程序看到的12号内存单元和操作系统实际给出的3,5号内存单元，就变成了两种不同的事物。
12号内存单元只是程序看到的，3,5号是真实的内存单元。我们把前者称为虚拟内存单元，后者指为物理
内存单元。  </p>

<p>有了虚拟内存的概念后，程序就无法无天了，全部的内存我都可以用，想访问哪块访问哪块，至于
实际上真正访问的是内存哪个位置，我可不关心，那是操作系统的事，我只要把一个虚拟内存号告诉
操作系统就可以了。所以，从程序看来，他拥有整个内存空间。  </p>

<p>严格来说，<code>程序</code>这个词是不准确的, <code>程序</code>一般就是指的代码本身。但是代码一旦运行起来，
和这段代码相关的东西就太多了,比如指令，数据，映射表，用到的内存。另一方面，
系统中有多个程序在执行，有时候程序A执行，有时候程序B执行，操作系统从A切换到B时，
肯定要记下来A执行到哪里了，这也和程序相关。所以这时候，我们又抽象出一个概念，叫<code>进程</code>。
这时候，<code>程序</code>就表示硬盘上那块代码，<code>进程</code>表示正在运行的程序，<code>进程</code>不仅包含代码，
还包含一些运行时相关的东西。</p>

<p>现在，当你启动一个程序时，操作系统会先创建一个进程，为这个进程建立一个私有的虚拟的内存空间，
把程序代码加载进来。进程代表一个运行中的程序，程序在运行时要使用内存，并且使用内存的方式多种多样，
程序有有些数据放在内存中是不变的，有些是一开始就分配好的，还有一些会根据需要分配。所以，
我们需要对进程的虚拟内存空间进行良好的组织，以便操作系统和程序配合，高效地完成任务。  </p>

<p>下图是一个Linux进程的虚拟内存空间</p>

<p><img src="/assets/blog-images/vir_mem.png" alt="vir_mem"></p>

<p>所有的Linux进程的虚拟内存空间都是以这种方式组织的，只不过不同进程因为映射表不同，所以
同一虚拟地址对应不同的物理地址。如果进程需要共享一块内存区，只需要在映射表中把同一虚拟内存
地址映射到相同物理地址就可以了，比如上图中的Kernel virutal memory区域，这个区域是操作系统
内核的代码，所有进程都需要共享，所以操作系统就可以把所有进程的这一区域映射到相同物理地址处。</p>

<p>上图的下半部分是Process virtual memory，代码进程使用的虚拟内存空间，可以看出他们被分成了
几个块，这些块代表了程序使用内存的不同方式。我们先来看一段代码，并结合上图说明一下程序使用
内存的不同方式。</p>

<h2>示例3</h2>
<div class="highlight"><pre><code class="c language-c" data-lang="c"><span class="cp">#include &lt;stdio.h&gt;</span>
<span class="cp">#include &lt;stdlib.h&gt;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="s">&quot;hello&quot;</span><span class="p">;</span>
    <span class="kt">char</span> <span class="n">q</span><span class="p">[]</span> <span class="o">=</span> <span class="s">&quot;world&quot;</span><span class="p">;</span>
    <span class="kt">char</span> <span class="o">*</span><span class="n">r</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span><span class="p">)</span><span class="o">*</span><span class="mi">6</span><span class="p">);</span>

    <span class="n">p</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;s&#39;</span><span class="p">;</span>
    <span class="n">q</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;s&#39;</span><span class="p">;</span>
    <span class="n">r</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;s&#39;</span><span class="p">;</span>

    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;p is:%s&quot;</span><span class="p">,</span><span class="n">p</span><span class="p">);</span>
    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;q is:%s&quot;</span><span class="p">,</span><span class="n">q</span><span class="p">);</span>
    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;r is:%s&quot;</span><span class="p">,</span><span class="n">r</span><span class="p">);</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>我们先用gcc将这段代码编程成汇编语言</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">gcc -S tchar.c -o tchar.s
</code></pre></div>
<h2>示例3汇编版本（含注释, 只含关键代码)</h2>
<div class="highlight"><pre><code class="gas language-gas" data-lang="gas"><span class="na">.file</span>   <span class="s">&quot;tcharp.c&quot;</span>
    <span class="na">.section</span>    <span class="no">.rodata</span>
<span class="nl">.LC0:</span>
    <span class="na">.string</span> <span class="s">&quot;hello&quot;</span>
<span class="nl">.LC1:</span>
    <span class="na">.string</span> <span class="s">&quot;p is:%s&quot;</span>
<span class="nl">.LC2:</span>
    <span class="na">.string</span> <span class="s">&quot;q is:%s&quot;</span>
<span class="nl">.LC3:</span>
    <span class="na">.string</span> <span class="s">&quot;r is:%s&quot;</span>
    <span class="na">.text</span>
    <span class="na">.globl</span>  <span class="no">main</span>
    <span class="na">.type</span>   <span class="no">main</span><span class="p">,</span> <span class="na">@function</span>
<span class="nl">main:</span>
<span class="c"># char *p = &quot;hello&quot;</span>
    <span class="nf">movl</span>    <span class="no">$.LC0</span><span class="p">,</span> <span class="mi">28</span><span class="p">(</span><span class="nv">%esp</span><span class="p">)</span> 

<span class="c"># char q[] = &quot;world&quot;</span>
    <span class="nf">movl</span>    <span class="no">$1819438967</span><span class="p">,</span> <span class="mi">38</span><span class="p">(</span><span class="nv">%esp</span><span class="p">)</span> 
    <span class="no">movw</span>    <span class="no">$100</span><span class="p">,</span> <span class="mi">42</span><span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>

<span class="c"># char *r = (char *)malloc(sizeof(char)*6)</span>
    <span class="nf">movl</span>    <span class="no">$6</span><span class="p">,</span> <span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>
    <span class="nf">call</span>    <span class="no">malloc</span>
    <span class="nf">movl</span>    <span class="nv">%eax</span><span class="p">,</span> <span class="mi">32</span><span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>

<span class="c"># p[0] = &#39;s&#39;</span>
    <span class="nf">movl</span>    <span class="mi">28</span><span class="p">(</span><span class="nv">%esp</span><span class="p">),</span> <span class="nv">%eax</span>
    <span class="nf">movb</span>    <span class="no">$115</span><span class="p">,</span> <span class="p">(</span><span class="nv">%eax</span><span class="p">)</span>
<span class="c"># q[0] = &#39;s&#39;</span>
    <span class="nf">movb</span>    <span class="no">$115</span><span class="p">,</span> <span class="mi">38</span><span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>
<span class="c"># r[0] = &#39;s&#39;</span>
    <span class="nf">movl</span>    <span class="mi">32</span><span class="p">(</span><span class="nv">%esp</span><span class="p">),</span> <span class="nv">%eax</span>
    <span class="nf">movb</span>    <span class="no">$115</span><span class="p">,</span> <span class="p">(</span><span class="nv">%eax</span><span class="p">)</span>

    <span class="nf">movl</span>    <span class="no">$.LC1</span><span class="p">,</span> <span class="nv">%eax</span>
    <span class="nf">movl</span>    <span class="mi">28</span><span class="p">(</span><span class="nv">%esp</span><span class="p">),</span> <span class="nv">%edx</span> <span class="c"># save p</span>
    <span class="nf">movl</span>    <span class="nv">%edx</span><span class="p">,</span> <span class="mi">4</span><span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>
    <span class="nf">movl</span>    <span class="nv">%eax</span><span class="p">,</span> <span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>
    <span class="nf">call</span>    <span class="no">printf</span>

    <span class="nf">movl</span>    <span class="no">$.LC2</span><span class="p">,</span> <span class="nv">%eax</span>
    <span class="nf">leal</span>    <span class="mi">38</span><span class="p">(</span><span class="nv">%esp</span><span class="p">),</span> <span class="nv">%edx</span> <span class="c"># save q</span>
    <span class="nf">movl</span>    <span class="nv">%edx</span><span class="p">,</span> <span class="mi">4</span><span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>
    <span class="nf">movl</span>    <span class="nv">%eax</span><span class="p">,</span> <span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>
    <span class="nf">call</span>    <span class="no">printf</span>

    <span class="nf">movl</span>    <span class="no">$.LC3</span><span class="p">,</span> <span class="nv">%eax</span>
    <span class="nf">movl</span>    <span class="mi">32</span><span class="p">(</span><span class="nv">%esp</span><span class="p">),</span> <span class="nv">%edx</span> <span class="c"># save r</span>
    <span class="nf">movl</span>    <span class="nv">%edx</span><span class="p">,</span> <span class="mi">4</span><span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>
    <span class="nf">movl</span>    <span class="nv">%eax</span><span class="p">,</span> <span class="p">(</span><span class="nv">%esp</span><span class="p">)</span>
    <span class="nf">call</span>    <span class="no">printf</span>
</code></pre></div>
<p>从上述汇编代码可以看出p,q,r三种使用内存的方式。从初始化上看，
p指向的&quot;hello&quot;,初始化时，直接指向了一个固定的位置,这意味着代码执行的时候，
这个位置已经有数据了。q指向的&quot;world&quot;，初始化是由代码完成的，你把&quot;world&quot;经ASCII码转化成数字形式，
对比一下就会发现，那两个数字，1819438967,100,对应的就是&quot;world&quot;。而r的初始化，是调用malloc得到的。  </p>

<p>从这段汇编代码。我们从直觉上会感觉到这三种使用内存方式的不同，接下来，我们再来看一下Linux运行时存储器映像。</p>

<p><img src="/assets/blog-images/linux_runtime_mem_img.png" alt="linux_runtime_mem_img"></p>

<p>.text 段放着已经编译的程序机器代码。<br>
.rodata 段放着只读数据，<code>printf</code>函数参数中的字符串，p指向的&quot;hello&quot;，
都在这存着。正因为这个段是只读的，所以不能修改，代码   </p>
<div class="highlight"><pre><code class="c language-c" data-lang="c"><span class="n">p</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;s&#39;</span>
</code></pre></div>
<p>执行时就会出现段错误。<br>
.data 段放着已经初始化的全局变量，.bss 段变着没有初始化的全局变量。<br>
再往上是 Run-time heap, 我们用malloc分配的内存空间都在这一段。<br>
接着是User Stack，程序中的局部变量都在这一段，我们q指向的&quot;world&quot;就存储在这里。
从图中也可以看到,<code>%esp</code>指向栈顶，再回头看一下汇编代码，你可能就明白之前相对于(%esp)地址所做的操作意味着什么。</p>

<p>这里特别要区分 <strong>地址与数据</strong> 。<br>
p,q,r是局部变量，它们的值都是地址，这个地址作为局部变量的值，在User Stack里存储。<br>
p表示的地址指向数据&quot;hello&quot;,这是不可变量,在.rodata段中存储。q表示的地址指向的数据&quot;world&quot;,作为局部变量的数据，在User Stack段存储。
r表示的地址指向的数据，在Run-time heap中存储。  </p>

<p>为了验证我们的想法，我们做一个实验，把p,q,r三者地址打印出来, 再把三者指向的数据的地址打印出来。
然后查看内存分配。</p>

<h2>示例4</h2>
<div class="highlight"><pre><code class="c language-c" data-lang="c"><span class="cp">#include &lt;stdio.h&gt;</span>
<span class="cp">#include &lt;stdlib.h&gt;</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="s">&quot;hello&quot;</span><span class="p">;</span>
    <span class="kt">char</span> <span class="n">q</span><span class="p">[]</span> <span class="o">=</span> <span class="s">&quot;world&quot;</span><span class="p">;</span>
    <span class="kt">char</span> <span class="o">*</span><span class="n">r</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span><span class="p">)</span><span class="o">*</span><span class="mi">6</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">n</span><span class="p">;</span>

    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;addr of p:%p</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">p</span><span class="p">);</span>
    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;addr of q:%p</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">q</span><span class="p">);</span>
    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;addr of r:%p</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">r</span><span class="p">);</span>

    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;addr of p&#39;s data:%p</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">p</span><span class="p">);</span>
    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;addr of q&#39;s data:%p</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">q</span><span class="p">);</span>
    <span class="n">printf</span> <span class="p">(</span><span class="s">&quot;addr of r&#39;s data:%p</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>

    <span class="n">scanf</span> <span class="p">(</span><span class="s">&quot;%d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">n</span><span class="p">);</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>为了便于观察，我们引入scanf,同时放在后台运行，这样只要我们不输入数据，
进程就不会终止，我们就可以观察它。运行它，  </p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ ./tcharp  &amp;
[2] 3461
addr of p:0xbfaa91d8
addr of q:0xbfaa91e6
addr of r:0xbfaa91dc
addr of p&#39;s data:0x8048670
addr of q&#39;s data:0xbfaa91e6
addr of r&#39;s data:0x87ad008
</code></pre></div>
<p>从这里，我们可以看出:p,q,r本身的值，以及q指向的数据，存储的位置离的很近，我们猜测，
所以0xbfXXXXXX这一块应该是User Stack区域，0x8048XXX这一块是.rodata区域，
0x87XXXXX这一块是Run-time heap区域。</p>

<p>接下来，我们使用 <code>readelf</code> 命令，得到各个区域的实际位置，进一步明确我们的猜想。</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ readelf -a tcharp &gt; tcharp_elf.txt
</code></pre></div>
<p>从tcharp_elf.txt中截取关键数据, 得到</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">  [11] .init             PROGBITS        08048318 000318 00002e 00  AX  0   0  4
  [12] .plt              PROGBITS        08048350 000350 000060 04  AX  0   0 16
  [13] .text             PROGBITS        080483b0 0003b0 00023c 00  AX  0   0 16
  [14] .fini             PROGBITS        080485ec 0005ec 00001a 00  AX  0   0  4
  [15] .rodata           PROGBITS        08048608 000608 000077 00   A  0   0  4
  [16] .eh_frame_hdr     PROGBITS        08048680 000680 000034 00   A  0   0  4
  [17] .eh_frame         PROGBITS        080486b4 0006b4 0000c4 00   A  0   0  4
  [18] .ctors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        08049f1c 000f1c 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        08049f24 000f24 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049f28 000f28 0000c8 08  WA  6   0  4
  [22] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        08049ff4 000ff4 000020 04  WA  0   0  4
  [24] .data             PROGBITS        0804a014 001014 000008 00  WA  0   0  4
  [25] .bss              NOBITS          0804a01c 00101c 000008 00  WA  0   0  4
  [26] .comment          PROGBITS        00000000 00101c 00002a 01  MS  0   0  1
  [27] .shstrtab         STRTAB          00000000 001046 0000fc 00      0   0  1
  [28] .symtab           SYMTAB          00000000 0015f4 000430 10     29  45  4
  [29] .strtab           STRTAB          00000000 001a24 00022c 00      0   0  1
</code></pre></div>
<p>从这里，我们可以验证对 .rodata 段的猜测，p指向的 &quot;hello&quot;, 确实是存储在这一段。</p>

<p>然后，我们查看其它段的位置</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ cat /proc/3461/maps 
08048000-08049000 r-xp 00000000 08:0a 4981409    /home/zhaoxk/test/tcharp
08049000-0804a000 r--p 00000000 08:0a 4981409    /home/zhaoxk/test/tcharp
0804a000-0804b000 rw-p 00001000 08:0a 4981409    /home/zhaoxk/test/tcharp
087ad000-087ce000 rw-p 00000000 00:00 0          [heap]
b75fc000-b75fd000 rw-p 00000000 00:00 0 
b75fd000-b77a1000 r-xp 00000000 08:07 412678     /lib/i386-linux-gnu/libc-2.15.so
b77a1000-b77a3000 r--p 001a4000 08:07 412678     /lib/i386-linux-gnu/libc-2.15.so
b77a3000-b77a4000 rw-p 001a6000 08:07 412678     /lib/i386-linux-gnu/libc-2.15.so
b77a4000-b77a7000 rw-p 00000000 00:00 0 
b77c1000-b77c5000 rw-p 00000000 00:00 0 
b77c5000-b77c6000 r-xp 00000000 00:00 0          [vdso]
b77c6000-b77e6000 r-xp 00000000 08:07 403838     /lib/i386-linux-gnu/ld-2.15.so
b77e6000-b77e7000 r--p 0001f000 08:07 403838     /lib/i386-linux-gnu/ld-2.15.so
b77e7000-b77e8000 rw-p 00020000 08:07 403838     /lib/i386-linux-gnu/ld-2.15.so
bfa8b000-bfaac000 rw-p 00000000 00:00 0          [stack]
</code></pre></div>
<p>看到stack和heap段的位置了吧，再一次印证了我们的想法。</p>

<p>好了，我们的探索到这里就结束了。</p>

<hr>

<h1>文后的话</h1>

<p>从上面的过程可以看出，要想真正理解C语言，你需要了解汇编，需要了解操作系统，
而Linux提供了一系列工具，方便你探索整个系统的运行机制。如果你也想了解它，
请开始使用它。<br>
还是那句话。</p>

<blockquote>
<p>既然看起来不错，为什么不试试呢？</p>
</blockquote>

<hr>

<p>转载请注明出处： http://minixalpha.github.io/2013/10/25/charpointerarray.html</p>


      </article>

      <div class="comments">
        
          <div id="disqus_thread"></div>
 <script type="text/javascript">
     /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
     var disqus_shortname = 'minixalpha'; // required: replace example with your forum shortname

     /* * * DON'T EDIT BELOW THIS LINE * * */
     (function() {
         var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
         dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
         (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
     })();
 </script>
 <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
    

        
      </div>


      <footer>
        Copyright (c) minixalpha 2014
      </footer>

    </div>
  </body>
</html>
